/*
 *  Autores: Claudio Djohnnatha, David Guilherme, Jailson Lima e Jordan Lira.
 *
 *  Projeto da disciplina Linguagem de Programação 2.
 *
 *  Arquivo: EditorOnline.java
 *
 *  Data: 27/08/2013
 *
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataOutputStream;
import java.util.Hashtable;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class EditorOnline extends JFrame
{

    // Paineil de Texto.

    private MyTextPane pane;

    // Protocolo de escrita.
    private ProtocolWrite protocolWrite;

    // Menus, itens de menus e barra de menus.
    private JMenu arquivo;
    private JMenuItem novo;
    private JMenuItem salvar;
    private JMenuItem fechar;
    private JMenuItem renomear;
    private JMenuItem excluir;
    private JMenuItem sair;
    private JMenuBar bar;

    // Label para mostrar mensagens.
    private MessageLabel messageLabel;

    // Título do documento aberto.
    private JLabel titulo;

    // Painel de edição.
    private PanelColor panelColor;

    // Escreve Documentos:
    private JLabel labelDocuments;

    // Lista drop-down de documentos existentes no servidor.
    private JComboBox listDocuments;

    // Botão para abrir um documento selecionado.
    private JButton open;

    // Botão para atualizar a lista de documentos do servidor.
    private JButton updade;

    // Label para mostrar o loading quando o cliente estiver tentando se conectar ao servidor.
    private JLabel loading;

    // Variável para armazenar o título do documento atualmente aberto.
    private String titleDocument = "";

    // Mantém o status da conecção.
    private boolean connect = false;

    public EditorOnline()
    {
        super("Editor Online");

        // Configura o Editor.
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(20, 20, 732, 610); // 40, 40, 500, 300
        setResizable(false);
        setLayout(null);
        getContentPane().setBackground(new Color(210, 210, 210));

        // Evento de janela.
        addWindowListener(
                new WindowAdapter()
                {
                    public void windowClosing(WindowEvent event)
                    {
                        if (connect == true)
                        {
                            protocolWrite.desconnecting();
                        } else
                        {
                            System.exit(0);
                        }
                    }
                }
        );

        // Inicia os menus.
        initMenu();

        // Configura o Painel de Texto.
        pane = new MyTextPane();
        pane.setBounds(10, 10, 500, 540);
        pane.setFont(new Font("Arial", Font.PLAIN, 14));
        pane.setForeground(new Color(16, 16, 16));
        pane.setBackground(new Color(225, 225, 225));
        pane.setEnabled(false);
        add(pane);

        // Configura a Caixa de Rolagem do painel de texto.
        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(pane);
        scroll.setBounds(10, 10, 500, 540);
        add(scroll);

        // Inicia outros componentes.
        initComponents();

        // Cria o protocolo de escrita passanto o Painel de Texto para o seu construtor.
        protocolWrite = new ProtocolWrite(this);

        // Configura Look And Feel, para o software ter a mesma aparência do Windows.
        settingsLookAndFeel();

        // Configura o editor como visível.
        setVisible(true);
        

    } // fim do construtor.

   // Configura a referência para o ProtocolWrite do stream de saída (out) do ClientApplication, que irá se
    // conectar ao stream de entrada (in) do ProtocolServer associado a esse ClientApplication.
    public void setOutput(DataOutputStream out)
    {
        protocolWrite.setOutput(out);
    }

    // Método para escrever o texto sincrônizado pelo ProtocolComunication no Painel de Texto do editor.
    public void writeTextPane(String fromServer)
    {
        protocolWrite.writeTextPane(fromServer);
    }

    public MyTextPane getTextPane()
    {
        return pane;
    }

    // Aparência e Comportamento.
    public void settingsLookAndFeel()
    {
        try
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception exception)
        {
        }
    }

    public void initMenu()
    {
        // Menu Arquivo.
        arquivo = new JMenu("Arquivo");
        arquivo.setMnemonic('A');

        // Item de menu Novo Documento.
        novo = new JMenuItem("Novo Documento");
        novo.setMnemonic('N');
        arquivo.add(novo);
        novo.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            showMessageServer("Nao conectado ao Servidor!");
                            return;
                        }

                        int option = dialogNewDocument();

                        if (option == 0)
                        {
                            protocolWrite.newDocument(titleDocument);
                        }
                    }
                }
        );

        // Item de menu Salvar.
        salvar = new JMenuItem("Salvar");
        arquivo.add(salvar);
        salvar.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            return;
                        }

                        if (!pane.isEnabled())
                        {
                            return;
                        }

                        protocolWrite.saveDocument();
                    }
                }
        );

        // Item de menu Fechar.
        fechar = new JMenuItem("Fechar");
        arquivo.add(fechar);
        fechar.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            return;
                        }

                        if (pane.isEnabled())
                        {
                            protocolWrite.closeDocument();
                            titleDocument = "";
                        }
                    }
                }
        );

        // Item de menu Renomear.
        renomear = new JMenuItem("Renomear");
        arquivo.add(renomear);
        renomear.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            return;
                        }

                        if (!pane.isEnabled())
                        {
                            return;
                        }

                        int option = dialogRenameDocument();

                        if (option == 0)
                        {
                            protocolWrite.renameDocument(titleDocument);
                        }
                    }
                }
        );

        // Item de menu Excluir.
        excluir = new JMenuItem("Excluir");
        arquivo.add(excluir);
        excluir.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            return;
                        }

                        if (pane.isEnabled())
                        {
                            int option = JOptionPane.showConfirmDialog(null, "Deseja realmente excluir o documento?", "Excluir Documento", JOptionPane.YES_NO_OPTION);

                            if (option == 0) // Optou por excluir.
                            {
                                protocolWrite.deleteDocument();
                            }
                        }
                    }
                }
        );

        arquivo.addSeparator();

        // Item de menu Sair.
        sair = new JMenuItem("Sair");
        arquivo.add(sair);
        sair.addActionListener(
                new ActionListener() // Classe interna anônima.
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        int opcao = JOptionPane.showConfirmDialog(null, "Deseja realmente sair?", "Sair", JOptionPane.YES_NO_OPTION);

                        if (opcao == 0)
                        {
                            if (connect == true)
                            {
                                protocolWrite.desconnecting();
                                System.exit(0);
                            } else
                            {
                                System.exit(0);
                            }
                        }
                    }
                }
        );

        // Barra de menus.
        bar = new JMenuBar();
        setJMenuBar(bar);
        bar.add(arquivo); // Adiciona o menu Arquivo à barra de menus.

    } // fim do método initMenu.

    public void initComponents()
    {
        // Label para mostrar mensagens.
        messageLabel = new MessageLabel();
        messageLabel.setLocation(734, 5);
        add(messageLabel);

        // Label com o título do documento aberto.
        titulo = new JLabel();
        titulo.setBounds(10, 10, 500, 40);
        titulo.setForeground(new Color(64, 64, 64));
        titulo.setFont(new Font("Arial", Font.BOLD, 16));
        titulo.setVisible(false);
        add(titulo);

        // Painel de seleção de cor do texto.
        panelColor = new PanelColor(pane);
        panelColor.setBounds(520, 10, 196, 540);
        add(panelColor);

        // Label para escrever Documentos:.
        labelDocuments = new JLabel("Documentos:");
        labelDocuments.setBounds(10, 120, 180, 30);
        labelDocuments.setForeground(new Color(96, 96, 96));
        labelDocuments.setFont(new Font("Arial", Font.BOLD, 14));
        panelColor.add(labelDocuments);

        // Lista drop-down com a lista de documentos do servidor.
        listDocuments = new JComboBox();
        listDocuments.setMaximumRowCount(10);
        listDocuments.setBounds(10, 155, 176, 25);
        listDocuments.setFont(new Font("Arial", Font.PLAIN, 12));
        panelColor.add(listDocuments);

        // Botão para abrir um documento selecionado.
        open = new JButton("Abrir");
        open.setBounds(9, 190, 70, 25);
        open.setFont(new Font("Arial", Font.PLAIN, 12));
        panelColor.add(open);

        open.addActionListener(
                new ActionListener()
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            showMessageServer("Nao conectado ao Servidor!");
                            return;
                        }

                        if (listDocuments.getItemCount() == 0)
                        {
                            showMessageServer("Nao ha documentos salvos!");
                            return;
                        }

                        int index = listDocuments.getSelectedIndex();

                        titleDocument = (String) listDocuments.getItemAt(index);

                        protocolWrite.openDocument(titleDocument);
                    }
                }
        );

        // Botão para atualizar a lista de documentos do servidor.
        updade = new JButton("Atualizar");
        updade.setBounds(84, 190, 103, 25);
        updade.setFont(new Font("Arial", Font.PLAIN, 12));
        panelColor.add(updade);

        updade.addActionListener(
                new ActionListener()
                {
                    public void actionPerformed(ActionEvent event)
                    {
                        if (connect == false)
                        {
                            showMessageServer("Nao conectado ao Servidor!");
                            return;
                        }

                        protocolWrite.listDocuments();
                    }
                }
        );

        // Icone do loanding.
        Icon icon = new ImageIcon(getClass().getResource("imagens/loading32.gif"));

        // Label para mostrar o loading quando o cliente estiver tentando se conectar ao servidor.
        loading = new JLabel("  LOADING...", icon, SwingConstants.CENTER);
        loading.setBounds(10, 260, 180, 80);
        loading.setForeground(new Color(96, 96, 96));
        loading.setFont(new Font("Arial", Font.BOLD, 14));
        // loading.setIcon(  );
        panelColor.add(loading);

    } // fim de initComponents.

    public void enableTitle()
    {
        titulo.setText(titleDocument);
        titulo.setVisible(true);
    }

    public void disableTitle()
    {
        titulo.setVisible(false);
        titleDocument = "";
    }

    public void renameTitle(String new_title)
    {
        titleDocument = new_title;
        titulo.setText(titleDocument);
    }

    public int dialogNewDocument()
    {
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setPreferredSize(new Dimension(268, 50));
        panel.setBackground(new Color(210, 210, 210));

        JLabel titleLabel = new JLabel("T\u00edtulo do Documento:");
        titleLabel.setBounds(10, 10, 180, 20);
        final JTextField titleField = new JTextField();
        titleField.setBounds(115, 10, 140, 20);

        panel.add(titleLabel);
        panel.add(titleField);

        String[] options = new String[]
        {
            "OK", "Cancelar"
        };

        int option = JOptionPane.showOptionDialog(this, panel, "T\u00edtulo do Documento", JOptionPane.NO_OPTION, JOptionPane.PLAIN_MESSAGE,
                null, options, options[ 0]);

        if (titleField.getText().trim().equals(""))
        {
            titleDocument = "Documento sem t\u00edtulo";
        } else
        {
            titleDocument = titleField.getText();
        }

        return option; // Se option for igual a 0, o usuário clicou em OK, caso contrário ele clicou em Cancelar ou fechou a caixa de dialogo.
    }

    public int dialogRenameDocument()
    {
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setPreferredSize(new Dimension(255, 50));
        panel.setBackground(new Color(210, 210, 210));

        JLabel titleLabel = new JLabel("Novo T\u00edtulo:");
        titleLabel.setBounds(10, 10, 180, 20);
        final JTextField titleField = new JTextField();
        titleField.setBounds(75, 10, 170, 20);

        panel.add(titleLabel);
        panel.add(titleField);

        String[] options = new String[]
        {
            "OK", "Cancelar"
        };

        int option = JOptionPane.showOptionDialog(this, panel, "Renomear Documento", JOptionPane.NO_OPTION, JOptionPane.PLAIN_MESSAGE,
                null, options, options[ 0]);

        if (titleField.getText().trim().equals(""))
        {
            return 1;
        }

        titleDocument = titleField.getText();

        return option; // Se option for igual a 0, o usuário clicou em OK, caso contrário ele clicou em Cancelar ou fechou a caixa de dialogo.
    }

    // Recebe as atualizações da lista de documentos do servidor.
    public void updateListDocuments(String fromServer)
    {
      // TESTE
        // System.out.println( "ATUALIZACAO DE DOCUMENTOS RECEBIDA DO SERVIDOR:" );
        // System.out.println( fromServer );

        String[] tokens = fromServer.split(" ");

        // Verifica se a lista de documentos do servidor é vazia.
        if (tokens[ tokens.length - 2].equals("EMPTY"))
        {
            listDocuments.removeAllItems();
            return;
        }

        int size = tokens.length;
        int extremes_ranges = Integer.parseInt(tokens[ size - 2]);
        int index_initial = size - extremes_ranges - 2;

        String[] titles = new String[extremes_ranges - 1];

        for (int count = 0; count < titles.length; count++)
        {
            titles[ count] = fromServer.substring(Integer.parseInt(tokens[ index_initial + count]), Integer.parseInt(tokens[ index_initial + count + 1]));
        }

        // Atualiza a lista drop-down com os nomes dos clientes.
        listDocuments.removeAllItems();
        for (int count = 0; count < titles.length; count++)
        {
            listDocuments.addItem(titles[ count]);
        }
    }

    public void showMessageServer(String message)
    {
        if (messageLabel.getMessage().equals(message))
        {
            return;
        }

        // Instância o thread para mostrar a mensagem.
        ActiveMessage active = new ActiveMessage(messageLabel, message);
        active.start();
    }

    // Modifica o status da conecção com o servidor para conectado.
    public void connected()
    {
        connect = true;
        loading.setVisible(false);
    }

    // Modifica o status da conecção com o servidor para desconectado.
    public void desconnected()
    {
        connect = false;
        pane.setEnabled(false);
        pane.setBackground(new Color(225, 225, 225));
        showMessageServer("A coneccao com o Servidor caiu");
        loading.setVisible(true);
    }

    // Atualiza o estado do editor para que fique em um estado consistente, após a conecção ser reestabelecida.
    public void updateState()
    {
        connect = true;

        // Atualiza a lista de documentos do servidor.
        protocolWrite.listDocuments();

        // Verifica se tinha algum documento aberto, antes da conecção cair, e o atualiza.
        if (!titleDocument.equals(""))
        {
            for (int i = 0; i < listDocuments.getItemCount(); i++)
            {
                if (((String) listDocuments.getItemAt(i)).equals(titleDocument));
                {
                    protocolWrite.openDocument(titleDocument); // Atualiza o documento que estava aberto.
                    return;
                }
            }

         // Se a execução chegou nesse ponto é porque durante o tempo em que a conecção estava quebrada
            // o documento aberto foi excluido do servidor ou renomeado.
            showMessageServer("Falha no documento aberto!");
            disableTitle();
            pane.setText("");
            pane.setEnabled(false);
            pane.setBackground(new Color(225, 225, 225));
            titleDocument = "";
        }
        
    }

}
